package org.wu.framework.lazy.orm.database.sql.expand.database.persistence.method;

import org.framework.wu.framework.queue.Message;
import org.framework.wu.framework.queue.MessageQueue;
import org.framework.wu.framework.queue.MessageQueueFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wu.framework.core.CamelAndUnderLineConverter;
import org.wu.framework.core.ReflexUtils;
import org.wu.framework.core.stereotype.MethodParamFunction;
import org.wu.framework.core.utils.ObjectUtils;
import org.wu.framework.lazy.orm.core.persistence.conf.LazyTableFieldEndpoint;
import org.wu.framework.lazy.orm.core.persistence.map.EasyHashMap;
import org.wu.framework.lazy.orm.core.persistence.map.StringRowMap;
import org.wu.framework.lazy.orm.core.persistence.util.SqlMessageFormatUtil;
import org.wu.framework.lazy.orm.core.source.SqlSourceClass;
import org.wu.framework.lazy.orm.database.lambda.domain.PersistenceRepository;
import org.wu.framework.lazy.orm.database.lambda.domain.PersistenceRepositoryFactory;
import org.wu.framework.lazy.orm.database.lambda.stream.LambdaTableType;
import org.wu.framework.translation.data.convert.LayerOperationConvert;
import org.wu.framework.translation.data.convert.LazyDataFactory;
import org.wu.framework.translation.data.schema.SchemaMap;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * description 抽象自定义数据库持久层操作方法
 *
 * @author Jia wei Wu
 * @date 2020/7/28 上午8:56
 */
public abstract class AbstractLazyOperationMethod implements LazyOperationMethod {


    private final LazyOperationParameter lazyOperationParameter;
    Logger log = LoggerFactory.getLogger(AbstractLazyOperationMethod.class);

    protected AbstractLazyOperationMethod(LazyOperationParameter lazyOperationParameter) {
        this.lazyOperationParameter = lazyOperationParameter;
    }

    /**
     * 是否基本数据类型
     *
     * @param clazz class
     * @return boolean
     * @author Jiawei Wu
     * @date 2021/1/3 12:54 下午
     * * @see LayerOperationConvert
     * * {@link LayerOperationConvert}
     **/
    @Deprecated
    public static boolean isWrapClass(Class<?> clazz) {
        try {
            if (String.class.isAssignableFrom(clazz)) {
                return true;
            }
            if (Byte[].class.isAssignableFrom(clazz)) {
                return true;
            }
            if (Byte.class.isAssignableFrom(clazz)) {
                return true;
            }
            if (byte[].class.isAssignableFrom(clazz)) {
                return true;
            }
            if (byte.class.isAssignableFrom(clazz)) {
                return true;
            }
            return ((Class) clazz.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取 LazyOperationParameter
     *
     * @return LazyOperationParameter
     */
    protected LazyOperationParameter lazyOperationParameter() {
        return this.lazyOperationParameter;
    }

    /**
     * 创建 预执行SQL需要的属性
     *
     * @return 预执行SQL需要的属性
     */
    protected PersistenceRepository createPersistenceRepository() {
        if (ObjectUtils.isEmpty(lazyOperationParameter())) {
            return PersistenceRepositoryFactory.create();
        }
        return PersistenceRepositoryFactory.create(lazyOperationParameter().getLazyOperationAttribute());
    }

    /**
     * description 通过参数获取持久性存储库对象
     *
     * @param sourceParams 参数
     * @return PersistenceRepository 持久层对象
     * @author Jia wei Wu
     * @date 2021/4/17 3:38 下午
     **/
    @Override
    public PersistenceRepository analyzePersistenceRepository(Object[] sourceParams) {
        PersistenceRepository persistenceRepository;
        try {
            persistenceRepository = doAnalyzePersistenceRepository(sourceParams);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        lazyOperationParameter().getSqlInterceptorAdapter().interceptor(persistenceRepository);
        return persistenceRepository;
    }

    /**
     * 执行解析
     *
     * @param sourceParams 原始数据
     * @return 解析后的 PersistenceRepository 对象
     */

    public abstract PersistenceRepository doAnalyzePersistenceRepository(Object[] sourceParams) throws Exception;

    /**
     * describe  执行SQL 语句
     *
     * @param connection   当前线程链接对象
     * @param sourceParams 原始参数
     * @return Object 返回对象
     * @author Jia wei Wu
     * @date 2022/1/2 8:10 下午
     **/
    @Override
    public Object execute(Connection connection, Object[] sourceParams) throws Exception {
//        StopWatch stopWatch = new StopWatch();
//
//        stopWatch.start();
        Object o = doExecute(connection, sourceParams);
//        stopWatch.stop();
//        log.debug("SQL执行时间(秒):"+stopWatch.getTotalTimeMillis());
        return o;
    }

    /**
     * describe  执行SQL 语句
     *
     * @param
     * @return
     * @author Jia wei Wu
     * @date 2022/1/2 8:10 下午
     **/
    public Object doExecute(Connection connection, Object[] sourceParams) throws Exception {
        for (Object param : sourceParams) {
            PreparedStatement preparedStatement = connection.prepareStatement(analyzePersistenceRepository(new Object[]{param}).getQueryString());
            try {
                return preparedStatement.execute();
            } catch (SQLException sqlException) {
                throw sqlException;
            } finally {
                preparedStatement.close();
            }
        }
        return null;
    }

    /**
     * @param connection 数据源
     * @param param      单个对象或是单条记录
     * @return describe 精准执行
     * @author Jia wei Wu
     * @date 2021/4/18 10:13 上午
     **/
    public Object accurateDoExecution(Connection connection, Object param) throws Exception {
        return executionFunction(connection, preparedStatement -> {
            preparedStatement.execute();
            return preparedStatement;
        }, param);
    }

    /**
     * @param connection          数据源
     * @param methodParamFunction 返回数据中含有 PreparedStatement
     * @param param               参数
     * @return 执行结果
     * describe 执行函数
     * @author Jia wei Wu
     * @date 2021/4/18 10:46 上午
     **/
    public Object executionFunction(Connection connection, MethodParamFunction<PreparedStatement> methodParamFunction, Object param) throws Exception {
        PersistenceRepository persistenceRepository = analyzePersistenceRepository(new Object[]{param});
        PreparedStatement preparedStatement = connection.prepareStatement(persistenceRepository.getQueryString());
        try {
            return methodParamFunction.defaultMethod(preparedStatement);
        } finally {
            preparedStatement.close();
        }
    }


    /**
     * description 结果集转换器
     *
     * @param resultSet  结果集
     * @param resultType 返回结果类型字符串
     * @return List
     * @throws SQLException,NoSuchFieldException,InstantiationException,IllegalAccessException
     * @author Jia wei Wu
     * @date 2021/4/27 4:02 下午
     */
    public <E> List<E> resultSetConverter(ResultSet resultSet, String resultType) throws SQLException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        Class domainClass = null;
        try {
            domainClass = Class.forName(resultType);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return resultSetConverter(resultSet, domainClass);
    }

    /**
     * description 结果集转换器
     *
     * @param resultSet   结果集
     * @param domainClass 返回结果类型
     * @return List<E>
     * @exception/throws
     * @author Jia wei Wu
     * @date 2021/4/27 4:02 下午
     */
    public <E> List<E> resultSetConverter(ResultSet resultSet, Class<? extends E> domainClass) throws SQLException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //封装结果集
        List<E> sqlResult = new ArrayList<E>();//定义返回值

        //取出结果集的元信息：ResultSetMetaData
        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();

        // Map 数值
        if (Map.class.isAssignableFrom(domainClass)) {

            while (resultSet.next()) {
                Map rowMap = new HashMap<>();

                if (EasyHashMap.class.isAssignableFrom(domainClass)) {
                    rowMap = new EasyHashMap<>();
                    String tableName = resultSetMetaData.getTableName(1);
                    ((EasyHashMap) rowMap).setUniqueLabel(CamelAndUnderLineConverter.capitalizeFirstLetter(tableName));
                } else if (SchemaMap.class.isAssignableFrom(domainClass)) {
                    rowMap = new SchemaMap<>();
                } else if (StringRowMap.class.isAssignableFrom(domainClass)) {
                    rowMap = new StringRowMap();
                }
                //取出总列数
                int columnCount = resultSetMetaData.getColumnCount();
                //遍历总列数
                for (int i = 1; i <= columnCount; i++) {
                    //获取每列的名称，列名的序号是从1开始的
                    String columnName = resultSetMetaData.getColumnName(i);
                    // 获取数据库列字段类型
                    String columnClassName = resultSetMetaData.getColumnClassName(i);
                    //根据得到列名，获取每列的值
                    Object columnValue = resultSet.getObject(i);
                    // as 别名
                    String columnLabel = resultSetMetaData.getColumnLabel(i);
                    // 优先使用as
                    columnName = ObjectUtils.isEmpty(columnLabel) ? columnName : columnLabel;
//                        if(null==columnValue)columnValue=JavaBasicTypeDefaultValue.DEFAULT_CLASS_NAME_VALUE_HASHMAP.get(columnClassName);
                    if (EasyHashMap.class.isAssignableFrom(domainClass)) {
                        ((EasyHashMap) rowMap).put(CamelAndUnderLineConverter.lineToHumpField(columnName), columnValue, columnClassName);
                    } else if (SchemaMap.class.isAssignableFrom(domainClass)) {
                        rowMap.put(CamelAndUnderLineConverter.lineToHumpField(columnName), columnValue);
                    } else {
                        rowMap.put(columnName, columnValue);
                    }

                }
                //把赋好值的对象加入到集合中
                sqlResult.add((E) rowMap);
            }

        } else if (isWrapClass(domainClass)) {
            //基本数据类型
            while (resultSet.next()) {
//                Object convertBasicTypeBean = JavaBasicTypeDefaultValue.convertBasicTypeBean(domainClass, resultSet.getObject(1));
                Object rowData = resultSet.getObject(1);
                E handler = LazyDataFactory.handler(rowData, domainClass);
                sqlResult.add(handler);
            }
        } else {
            List<?extends LazyTableFieldEndpoint> convertedFieldList = SqlSourceClass.getInstance(domainClass).getLazyTableEndpoint().getLazyTableFieldEndpointList();

            // 驼峰字段
            Map<String, String> convertedFieldMap = convertedFieldList.stream().collect(Collectors.toMap(LazyTableFieldEndpoint::getName, LazyTableFieldEndpoint::getName));
            // 下划线字段
            convertedFieldMap.putAll(convertedFieldList.stream().collect(Collectors.toMap(lazyTableFieldEndpoint -> CamelAndUnderLineConverter.humpToLine2(lazyTableFieldEndpoint.getName()), LazyTableFieldEndpoint::getName)));


            // 获取查询结果返回的字段
            //取出总列数
            int columnCount = resultSetMetaData.getColumnCount();

            // 缓存返回字段和需要序列化对象的关系
            ConcurrentHashMap<Integer,Field>  cacheField=new ConcurrentHashMap<>();

            for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
                String columnName = resultSetMetaData.getColumnName(columnIndex).toLowerCase();
                columnName = CamelAndUnderLineConverter.lineToHumpField(columnName);
                // 表别名 优先
                String columnLabel = resultSetMetaData.getColumnLabel(columnIndex);
                String fieldName = convertedFieldMap.getOrDefault(columnLabel, convertedFieldMap.getOrDefault(columnName, null));
                if (ObjectUtils.isEmpty(fieldName)) {
                    continue;
                }
                //根据得到列名，获取每列的值
                Field field = domainClass.getDeclaredField(fieldName);
                field.setAccessible(true);
                cacheField.put(columnIndex,field);
            }
            while (resultSet.next()) {
                //实例化要封装的实体类对象
                E e = ReflexUtils.newInstance(domainClass);;

                //遍历总列数
                for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
                    //获取每列的名称，列名的序号是从1开始的
                    Field field = cacheField.get(columnIndex);
                    Object object = resultSet.getObject(columnIndex);
                    LazyDataFactory.handler(e, field, object);
                }
                //把赋好值的对象加入到集合中
                sqlResult.add(e);
            }
        }
        return sqlResult;
    }

    /**
     * 装载sql参数
     */
    public String loadSqlParameters(String sqlFormat, Object... params) {
        Object[] objects = Arrays.stream(params).map(o -> o).toArray(Object[]::new);
        PersistenceRepository persistenceRepository = PersistenceRepositoryFactory.create();
        String sql = SqlMessageFormatUtil.format(sqlFormat, objects);
//        String.format(sqlFormat, params);
        persistenceRepository.setQueryString(sql);
        return persistenceRepository.getQueryString();
    }

    /**
     * 获取orm对应的事件队列名称
     *
     * @return orm对应的事件队列
     */
    public MessageQueue getLazyOrmMessageQueue() {
        String eventQueueName = lazyOperationParameter.getLazyOperationAttribute().getEventQueueName();
        return MessageQueueFactory.getQueue(eventQueueName);
    }

    /**
     * 发送orm执行事件
     *
     * @param lambdaTableType 执行类型
     * @param body            执行对象
     */
    public void sendLazyOrmEvent(LambdaTableType lambdaTableType, Object body) {
        Message message = new Message(lambdaTableType.name(), body);
        getLazyOrmMessageQueue().send(message);
    }

}
